/**
 * @author Tobias Boehm
 *
 * 01.06.2011
 */
package org.anddev.andengine.extension.tbsengine.match;

import java.util.ArrayList;
import java.util.ListIterator;

import org.anddev.andengine.extension.tbsengine.match.gamestate.AbsGlobalGameState;
import org.anddev.andengine.extension.tbsengine.match.gamestate.AbsPlayerGameState;

/**
 * An instance of this class represents a round of a {@link AbsMatch}. It also
 * creates and manages all turns which are played this round. If a turn is
 * completed you can call {@link #startNextTurn()} to start the next one.
 * <p>
 * Notice:<br>
 * This class is in development and might be changed.
 * 
 *  
 * @author Tobias Boehm
 *
 * @param <PlayerGameStateClass> - Your implementation of {@link AbsPlayerGameState}.
 */
public class Round<PlayerGameStateClass extends AbsPlayerGameState> {

	/**
	 * A list of all turns which will be played this round.
	 */
	private final ArrayList<Turn> mTurns = new ArrayList<Turn>();
	
	/**
	 * An iterator which iterates over {@link #mTurns}.
	 */
	private ListIterator<Turn> mTurnIterator;
	
	/**
	 * The currently active turn.
	 */
	private Turn mCurrentTurn;
	
	/**
	 * A reference to the {@link AbsGlobalGameState} of which the round belongs to.
	 */
	private AbsGlobalGameState<?,PlayerGameStateClass,?> mGlobalGameState;
	
	/**
	 * The ID of this round.
	 */
	private final int mRoundID;

	/**
	 * A flag which indicates if the round is still open.
	 */
	private boolean mRoundOpen = false;
	
	
	/**
	 * The basic constructor for creating rounds.
	 * 
	 * @param pRoundID - The ID of this round.
	 * @param pGlobalGameState - A reference to the {@link AbsGlobalGameState} of which the round belongs to.
	 */
	public Round(final int pRoundID, final AbsGlobalGameState<?,PlayerGameStateClass,?> pGlobalGameState){
		
		this.mRoundID = pRoundID;
		
		this.mGlobalGameState = pGlobalGameState;
		
		this.createTurns();
	}
	
	private void createTurns(){
		
		int turnID = 0;
		
		for(PlayerGameStateClass currentPlayerGameState : this.mGlobalGameState.getPlayerGameStates()){
		
			if(!currentPlayerGameState.isDefeated()){
				
				mTurns.add(new Turn(turnID, currentPlayerGameState, this.mGlobalGameState));
				
				turnID++;
			}			
		}
		
		this.mTurnIterator = this.mTurns.listIterator();
	}
	
	/**
	 * This method starts the round and informs the {@link AbsGlobalGameState}
	 * about its start. Afterwards it also starts its first turn.
	 */
	public void startRound(){
		
		if(this.mRoundOpen){
			
			throw new IllegalStateException("The round is already running!");
		}
		
		this.mRoundOpen = true;
		
		this.mGlobalGameState.onRoundStarted(this);
		
		this.startNextTurn();
	}
	
	/**
	 * This method starts the next turn an informs the {@link AbsGlobalGameState}.
	 * If there is no turn left it will close the round as well as
	 * inform the {@link AbsGlobalGameState}.
	 */
	public void startNextTurn(){
		
		if(!this.mRoundOpen){
			
			throw new IllegalStateException("The round is already closed!");
		}
		
		if((this.mCurrentTurn != null) && this.mCurrentTurn.isTurnOpen()){
			
			throw new IllegalStateException("The current turn is stil open!");
		}
		
		if(this.mTurnIterator.hasNext()){
		
			final Turn nextTurn = this.mTurnIterator.next();
		
			if(nextTurn.getPlayerGameState().isDefeated()){
				
				// Delete the unnecessary turn.
				this.mTurnIterator.remove();
				
				this.startNextTurn();
				
			}else{
				
				this.mCurrentTurn = nextTurn;
				
				this.mCurrentTurn.startTurn();
				
				this.mGlobalGameState.onTurnStarted(this.mCurrentTurn);
			}
						
		}else{
			
			this.mRoundOpen = false;
			
			this.mGlobalGameState.onRoundCompleted(this);
		}
	}
	
	/**
	 * @return the mRoundOpen
	 */
	public boolean isRoundOpen() {
		return mRoundOpen;
	}

	/**
	 * @return the mRoundID
	 */
	public int getRoundID() {
		return mRoundID;
	}

	/**
	 * @return the mCurrentTurn
	 */
	public Turn getCurrentTurn() {
		return mCurrentTurn;
	}

	/**
	 * @return the mTurns
	 */
	public ArrayList<Turn> getTurns() {
		return mTurns;
	}
}
